<template>
  <div class="app-container">
    <!-- 顶部装饰区域 -->
    <div class="top-decoration">
      <div class="logo">
        <img src="../assets/images/img.png" alt="无人机控制平台">
        <span style="font-size: 30px;color: white;font-family: 'Adobe 繁黑體 Std B';margin-left: 350px">基于FMT的无人机多端协同作业系统</span>
      </div>
      <div class="status-indicator">
        <div class="connection-status" :class="{ connected: isConnected }">
          {{ isConnected ? '已连接' : '未连接' }}
        </div>
        <div class="mode-indicator">
          当前模式: {{ customModeText }}
        </div>
        <button class="speed-mode-button" @click="showSpeedDialog = true">飞行设置</button>
        <button class="speed-mode-button" @click="showModeDialog = true">模式设置</button>
      </div>
    </div>

    <div class="main-content">
      <!-- 左侧面板（画布 + 任务中心） -->
      <div class="left-panel">
        <!-- 画布区域 -->
        <div class="map-container">
          <canvas ref="canvas"></canvas>
          <div class="scale-indicator"><p>{{ scaleText }}</p></div>
        </div>

        <!-- 任务中心 -->
        <div class="panel-section task-center">
          <div class="task-title">任务中心
            <button @click="fetchFlyTasks" class="refresh-button">
              <img src="../assets/images/bt_refresh.svg" alt="刷新"/>
            </button>
          </div>
          <div class="scroll">
            <div class="list">
              <div v-for="flyTaskData in flyTaskList" :key="flyTaskData.trackId" class="list-item">
                <img :src="flyTaskData.creatClient === 'PC' ? pcIcon : mobileIcon" class="task-icon"/>
                <div class="task-info">
                  <div class="task-row">{{ flyTaskData.flyTaskName }}</div>
                  <div class="task-row">
                    <span class="task-value">{{ flyTaskData.flyStartDate.replace('T', '  ') }}</span>
                  </div>
                </div>
                <button class="task-btn" @click="openTaskDialog(flyTaskData)">查看</button>
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- 右侧控制面板 -->
      <div class="right-panel">
        <!-- 飞行控制面板 -->
        <div class="panel-section">
          <h2 class="section-title">飞行控制</h2>
          <div class="button-row">
            <button class="control-button" @click="handleTakeoffOrLand">
              <img class="image_button"
                   :src="flightStatus ? 'src/assets/images/bt_land.svg' : 'src/assets/images/bt_takeoff.svg'"
                   :alt="flightStatus ? '降落' : '起飞'"/>
              <span class="button-label">{{ flightStatus ? '降落' : '起飞' }}</span>
            </button>
            <button class="control-button" @click="handleReturn" :disabled="!flightStatus">
              <img class="image_button" src="../assets/images/bt_return.svg" alt="返航"/>
              <span class="button-label">返航</span>
            </button>
          </div>
        </div>

        <!-- 轨迹绘制面板 -->
        <div class="panel-section">
          <h2 class="section-title">轨迹绘制</h2>
          <div class="button-row">
            <button class="control-button" @click="setDrawingModeLine">
              <img class="image_button" src="../assets/images/bt_line.svg" alt="直线"/>
              <span class="button-label">直线</span>
            </button>
            <button class="control-button" @click="setDrawingModeRectangle">
              <img class="image_button" src="../assets/images/bt_rectangle.svg" alt="矩形"/>
              <span class="button-label">矩形</span>
            </button>
            <button class="control-button" @click="setDrawingModeCircle">
              <img class="image_button" src="../assets/images/bt_cycle.svg" alt="圆形"/>
              <span class="button-label">圆形</span>
            </button>
          </div>
          <div class="button-row">
            <button class="control-button" @click="handleSend" :disabled="!flightStatus || isExecTask">
              <img class="image_button" :src="isExecTask ? 'src/assets/images/bt_wait.svg' : 'src/assets/images/bt_send.svg'"
                   :alt="isExecTask ? '等待' : '发送'"/>
              <span class="button-label">{{ isExecTask ? '等待' : '发送' }}</span>
            </button>
            <button class="control-button" @click="clearTrackList">
              <img class="image_button" src="../assets/images/bt_clear.svg" alt="清除"/>
              <span class="button-label">清除</span>
            </button>
          </div>
        </div>

        <!-- 飞行状态面板 -->
        <div class="panel-section">
          <h2 class="section-title">飞行状态</h2>
          <div class="status-grid">
            <div class="status-card">
              <div class="status-label">高度</div>
              <div class="status-value">{{ altitude }}<span class="status-unit">m</span></div>
            </div>
            <div class="status-card">
              <div class="status-label">速度</div>
              <div class="status-value">{{ speed }}<span class="status-unit">m/s</span></div>
            </div>
            <div class="status-card">
              <div class="status-label">航向角</div>
              <div class="status-value">{{ Math.round(yaw) }}<span class="status-unit">°</span></div>
            </div>
            <div class="status-card">
              <div class="status-label">飞行时间</div>
              <div class="status-value">{{ flightTime }}</div>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 底部飞行数据 -->
    <div class="bottom-data">
      <div class="data-item">
        <span class="data-label">系统状态:</span>
        <span class="data-value">{{ systemStatusText }}</span>
      </div>
      <div class="data-item">
        <span class="data-label">当前位置:</span>
        <span class="data-value">X: {{ ((local_x/100).toFixed(2))}}m, Y: {{ ((local_y/100).toFixed(2))}}m</span>
      </div>
      <div class="data-item">
        <span class="data-label">飞行模式:</span>
        <span class="data-value">{{ customModeText }}</span>
      </div>
      <div class="data-item">
        <span class="data-label">电池电压:</span>
        <span class="data-value">{{voltageBattery}}</span>
      </div>
    </div>
  </div>

  <!-- 其他元素保持不变 -->
  <div v-if="showContextMenu" :style="{ top: `${contextMenuPosition.y}px`, left: `${contextMenuPosition.x}px` }"
       class="context-menu">
    <ul>
      <li v-if="!isExecTask" @click="handleContextMenuAction('setSpeed')">设置速度</li>
      <li v-if="flightStatus && !isExecTask" @click="handleContextMenuAction('goToPoint')">飞行至该点</li>
      <li @click="handleContextMenuAction('setMode')">设置模式</li>
    </ul>
  </div>

  <!-- 速度设置弹窗 -->
  <div v-if="showSpeedDialog" class="dialog-overlay" @click="closeSpeedDialog">
    <div class="dialog" @click.stop>
      <h3>设置速度和高度</h3>
      <div class="setting-item">
        <label for="speed-range">速度：</label>
        <input type="range" id="speed-range" v-model="speedValue" min="0.01" max="3" step="0.05"/>
        <p>当前速度: {{ speedValue }}m/s</p>
      </div>
      <div class="setting-item">
        <label for="altitude-range">高度：</label>
        <input type="range" id="altitude-range" v-model="altitudeValue" min="0.1" max="10" step="0.1"/>
        <p>当前高度: {{ altitudeValue }}m</p>
      </div>
      <div class="button-container">
        <button @click="confirmSpeedAndAltitude">确认</button>
        <button @click="closeSpeedDialog">取消</button>
      </div>
    </div>
  </div>

  <!-- 模式设置弹窗 -->
  <div v-if="showModeDialog" class="dialog-overlay" @click="closeModeDialog">
    <div class="dialog" @click.stop>
      <h3>设置模式</h3>
      <select v-model="selectedMode">
        <option value="手动Manual">手动Manual</option>
        <option value="自稳Stabilized">自稳Stabilized</option>
        <option value="特技Acro">特技Acro</option>
        <option value="定高Altitude">定高Altitude</option>
        <option value="板外Offboard">板外Offboard</option>
        <option value="定点Position">定点Position</option>
        <option value="任务Mission">任务Mission</option>
        <option value="返航return">返航return</option>
      </select>
      <div class="button-container">
        <button @click="confirmMode">确认</button>
        <button @click="closeModeDialog">取消</button>
      </div>
    </div>
  </div>

  <div v-if="showModeDialog" class="dialog-overlay" @click="closeModeDialog">
    <div class="dialog" @click.stop>
      <h3>设置模式</h3>
      <select v-model="selectedMode">
        <option value="手动Manual">手动Manual</option>
        <option value="自稳Stabilized">自稳Stabilized</option>
        <option value="特技Acro">特技Acro</option>
        <option value="定高Altitude">定高Altitude</option>
        <option value="板外Offboard">板外Offboard</option>
        <option value="定点Position">定点Position</option>
        <option value="任务Mission">任务Mission</option>
        <option value="返航return">返航return</option>
      </select>
      <div class="button-container">
        <button @click="confirmMode">确认</button>
        <button @click="closeModeDialog">取消</button>
      </div>
    </div>
  </div>

  <!-- 任务信息弹窗 -->
  <div v-if="showTaskDialog" class="dialog-overlay" @click="closeTaskDialog">
    <div class="dialog" style="width: 500px; height: 300px" @click.stop>
      <div class="dialog-header">
        <h3>任务信息</h3>
        <button class="close-btn" @click="closeTaskDialog">×</button>
      </div>

      <div class="dialog-content">
        <div class="task-info-item">
          <span class="info-label">任务ID:</span>
          <span class="info-value">{{ currentTask?.id || '-' }}</span>
        </div>

        <div class="task-info-item">
          <span class="info-label">任务名称:</span>
          <span class="info-value">{{ currentTask?.flyTaskName || '-' }}</span>
        </div>

        <div class="task-info-item">
          <span class="info-label">创建端:</span>
          <span class="info-value">
            <img :src="currentTask?.creatClient === 'PC' ? pcIcon : mobileIcon" class="client-icon" />
            {{ currentTask?.creatClient === 'PC' ? '电脑端' : '移动端' }}
          </span>
        </div>

        <div class="task-info-item">
          <span class="info-label">开始时间:</span>
          <span class="info-value">{{ formatDateTime(currentTask?.flyStartDate) || '-' }}</span>
        </div>

        <div class="task-info-item">
          <span class="info-label">轨迹ID:</span>
          <span class="info-value">{{ currentTask?.trackId || '-' }}</span>
        </div>

        <div class="task-info-item">
          <span class="info-label">轨迹数据:</span>
          <span class="info-value track-data">
            {{ currentTask?.flyTrackData ? '已包含轨迹数据' : '无轨迹数据' }}
          </span>
        </div>
      </div>

      <div class="dialog-footer">
        <button class="btn cancel-btn" @click="closeTaskDialog">关闭</button>
<!--        <button class="btn confirm-btn" @click="showTrack">查看轨迹</button>-->
      </div>
    </div>
  </div>
</template>

<script setup>
import {onMounted, onUnmounted, ref, watch} from 'vue';
import {fabric} from 'fabric';
import LineData from "@/model/LineData.js";
import RectangleData from "@/model/RectangleData.js";
import CircleData from "@/model/CircleData.js";
import airplaneImage from '../assets/images/img_plane.svg';
import homeImage from '../assets/images/img_home.svg';
import axios from "axios";
import pcIcon from '../assets/images/PC.svg';
import mobileIcon from '../assets/images/mobile.svg';

// 任务弹窗状态
const currentTask = ref({
  id:1,
  flyTaskName:'默认示例',
  flyTrackData:'',
  flyStartDate:'2025-07-02',
  createClient:'PC',
  trackId:'1'
});

// 工具函数：格式化日期时间
const formatDateTime = (dateTime) => {
  if (!dateTime) return '';
  // 假设后端返回的是 ISO 格式字符串，如 "2024-07-10T11:51:00"
  return new Date(dateTime).toLocaleString();
};

// 打开任务弹窗
const openTaskDialog = (task) => {
  currentTask.value = task;
  showTaskDialog.value = true;
};

// 关闭任务弹窗
const closeTaskDialog = () => {
  showTaskDialog.value = false;
  currentTask.value = null;
};

// 执行任务
const showTrack = () => {
  if (currentTask.value) {
    // 这里执行任务逻辑，例如发送任务数据到无人机
    console.log('执行任务:', currentTask.value);
    showTaskDialog.value = false;
    // 通知父组件或触发其他操作
  }
};

// 状态变量
let voltageBattery = ref("")
let isFirst = ref(true);
let isFirstData = ref(true);
const canvas = ref(null);
let canvasConst = null;
let gridSpacing = 50;
let isDragging = false;
let lastPosX = 0;
let lastPosY = 0;
const current_x = ref(0);
const current_y = ref(0);
const local_x = ref(0);
const local_y = ref(0);
const pre_x = ref(0);
const pre_y = ref(0);
const home_x = ref(0);
const home_y = ref(0);
const scale = ref(1);
const scaleText = ref("Scale: 100%");
let isDrawing = false;
const drawingMode = ref(null);
const trackDataList = ref([]);
let yaw = ref(0);
let roll = ref(0);
let pitch = ref(0);
let flightTime = ref('00:00:00');
let timer = null;
let speed = ref('0.0');
let altitude = ref('0.0');
let flightStatus = ref(false);
let isExecTask = ref(false);
const showContextMenu = ref(false);
const contextMenuPosition = ref({x: 0, y: 0});
const showSpeedDialog = ref(false);
const showModeDialog = ref(false);
const showTaskDialog = ref(false);
const speedValue = ref(0.2);
const altitudeValue = ref(1.0); // 默认高度
const customModeText = ref('未知');
const systemStatusText = ref('未解锁');
const clickToPoint = ref(null);
const selectedMode = ref('定点模式');
const flyTaskList = ref([]);
const isConnected = ref(false);
let ws = null;

// 方法
const handleContextMenuAction = async (action) => {
  showContextMenu.value = false;
  if (action === 'setSpeed') {
    showSpeedDialog.value = true;
  } else if (action === 'goToPoint') {
    try {
      isExecTask.value = true;
      const deltaX = clickToPoint.value.y - local_x.value;
      const deltaY = clickToPoint.value.x - local_y.value;
      let distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY) / 100.0;

      await axios.post('http://localhost:9090/drone/flyLine', {
        startX: local_x.value / 100.0,
        startY: local_y.value / 100.0,
        endX: -clickToPoint.value.y / 100.0,
        endY: clickToPoint.value.x / 100.0,
        flightAltitude: 0.5,
        duration_s: distance / speedValue.value
      });

      current_x.value = clickToPoint.value.x;
      current_y.value = clickToPoint.value.y;

    } catch (error) {
      console.error('Flight to point request failed:', error);
    } finally {
      isExecTask.value = false;
    }
  } else if (action === 'setMode') {
    showModeDialog.value = true;
  }
};

const handleContextMenu = (opt) => {
  contextMenuPosition.value = {x: opt.e.clientX, y: opt.e.clientY};
  clickToPoint.value = canvasConst.getPointer(opt.e);
  showContextMenu.value = true;
};

const handleClickOutside = () => {
  showContextMenu.value = false;
};

const closeSpeedDialog = () => {
  showSpeedDialog.value = false;
};

const banContextMenu = (event) => {
  event.preventDefault();
};

const confirmSpeedAndAltitude = () => {
  console.log(`设置的速度: ${speedValue.value} m/s`);
  console.log(`设置的高度: ${altitudeValue.value} m`);
  closeSpeedDialog();
};

const closeModeDialog = () => {
  showModeDialog.value = false;
};


const confirmMode = () => {
  closeModeDialog();
};

const onMessage = (event) => {
  const message = JSON.parse(event.data);
  // console.log("message:"+event.data)
  // if(message.yaw !== undefined && message.yaw==0)
  if(message.yaw !== undefined && message.yaw == 0 && message.roll !== undefined && message.roll ==0 && message.pitch !== undefined && message.pitch ==0 &&message.x !== undefined &&message.x == 0 &&message.y !== undefined&&message.y == 0)
    isConnected.value = false;
  else
    isConnected.value = true;
  if (message.yaw !== undefined) {
    yaw.value = message.yaw / 3.14 * 180;
  }
  if (message.roll !== undefined) {
    roll.value = -message.roll / 3.14 * 180;
  }
  if (message.pitch !== undefined) {
    pitch.value = message.pitch / 3.14 * 180;
  }
  if (message.x !== undefined) {
    local_x.value = message.x*100;
    // console.log("x:"+message.x)
  }
  if (message.y !== undefined) {
    local_y.value = message.y*100;
    // console.log("y:"+message.y)
  }
  if (message.z !== undefined) {
    altitude.value = message.z;
  }
  if (message.customModeText !== undefined) {
    customModeText.value = message.customModeText;
  }
  if (message.systemStatusText !== undefined) {
    systemStatusText.value = message.systemStatusText;
  }
  if (isFirstData.value) {
    pre_x.value = message.x * 100;
    pre_y.value = message.y * 100;
    current_x.value = message.y * 100;
    current_y.value = -message.x * 100;
    isFirstData.value = false;
  }
  if (message.groundSpeed !== undefined) {
    speed.value = message.groundSpeed;
  }
  if(message.battery !=undefined)
    voltageBattery.value = String(message.battery).substring(0,2)+"."+String(message.battery).substring(2,4)
  drawSmoothCurve(local_x.value, local_y.value);
};

const addAirplaneImage = () => {
  fabric.Image.fromURL(airplaneImage, (img) => {
    img.set({
      left: local_y.value,
      top: -local_x.value,
      originX: 'center',
      originY: 'center',
      scaleX: 0.15,
      scaleY: 0.15,
      selectable: false
    });
    canvasConst.add(img);
    img.on('added', () => {
      updateAirplanePositionAndRotation(img);
    });
  });
};

const addHomePositionImage = () => {
  if (flightStatus.value) {
    fabric.Image.fromURL(homeImage, (img) => {
      img.set({
        left: home_y.value,
        top: -home_x.value,
        originX: 'center',
        originY: 'center',
        scaleX: 0.15,
        scaleY: 0.15,
        selectable: false
      });
      canvasConst.add(img);
    });
  }
};

watch(yaw, () => {
  const img = canvasConst.getObjects().find(obj => obj.type === 'image');
  if (img) {
    updateAirplanePositionAndRotation(img);
  }
});

watch(systemStatusText, () => {
  if (systemStatusText.value === '解锁') {
    flightStatus.value = true;
  } else if (systemStatusText.value === '未解锁') {
    flightStatus.value = false;
  }
});

watch(flightStatus, () => {
  if (flightStatus.value) {
    startTimer();
    addHomePositionImage();
  } else {
    resetTimer();
  }
});

function startTimer() {
  let hours = 0, minutes = 0, seconds = 0;
  timer = setInterval(() => {
    seconds++;
    if (seconds === 60) {
      seconds = 0;
      minutes++;
    }
    if (minutes === 60) {
      minutes = 0;
      hours++;
    }
    flightTime.value = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
  }, 1000);
}

function resetTimer() {
  clearInterval(timer);
  flightTime.value = '00:00:00';
}

const updateAirplanePositionAndRotation = (img) => {
  img.set({
    left: local_y.value,
    top: -local_x.value,
    angle: yaw.value,
  });
  console.log("需要更新图片位置 x:"+local_y.value+";y:"+-local_x.value)
  canvasConst.renderAll();
};

const handleTakeoffOrLand = () => {
  if (!flightStatus.value) {
    axios.post('http://localhost:9090/drone/setAutoTakeoffMode')
        .then(response => {
          console.log('自动起飞请求成功', response);
          // 处理成功响应的逻辑
        })
        .catch(error => {
          console.error('自动起飞请求失败', error);
          // 处理请求失败的逻辑
        });
    flightStatus.value = true;
    addHomePositionImage();
  } else {
    isExecTask.value = false;
    axios.post('http://localhost:9090/drone/sendLandCommand')
        .then(response => {
          console.log('降落请求成功', response);
          // 处理成功响应的逻辑
        })
        .catch(error => {
          console.error('降落请求失败', error);
          // 处理请求失败的逻辑
        });
    flightStatus.value = false;
  }
};

const handleReturn = () => {
  isExecTask.value = false;
  axios.post('http://localhost:9090/drone/return')
      .catch(error => {
        console.error('自动返航请求失败', error);
      });
};

const handleSend = async () => {
  isExecTask.value = true;
  for (const trackData of trackDataList.value) {
    if (!isExecTask.value) break;

    try {
      if (trackData.type === 'line') {
        const deltaX = trackData.data.endX - trackData.data.startX;
        const deltaY = trackData.data.endY - trackData.data.startY;
        const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY) / 100.0;

        await axios.post('http://localhost:9090/drone/flyLine', {
          startX: trackData.data.startX / 100.0,
          startY: trackData.data.startY / 100.0,
          endX: trackData.data.endX / 100.0,
          endY: trackData.data.endY / 100.0,
          flightAltitude: altitudeValue.value,
          duration_s: distance / speedValue.value
        });

      } else if (trackData.type === 'rectangle') {
        const width = Math.abs(trackData.data.endX - trackData.data.startX);
        const height = Math.abs(trackData.data.endY - trackData.data.startY);
        const distance = 2 * (width + height) / 100.0;

        await axios.post('http://localhost:9090/drone/flyRectangleByP2P', {
          endX: trackData.data.endX / 100.0,
          endY: trackData.data.endY / 100.0,
          current_x: trackData.data.startX / 100.0,
          current_y: trackData.data.startY / 100.0,
          flightAltitude: altitudeValue.value,
          clockwise: true,
          cycle_s: distance / speedValue.value
        });

      } else if (trackData.type === 'circle') {
        const distance = 2 * Math.PI * trackData.data.radius / 100.0;

        await axios.post('http://localhost:9090/drone/flyCircle', {
          radius: trackData.data.radius / 100.0,
          clockwise: true,
          current_x: trackData.data.startX / 100.0,
          current_y: trackData.data.startY / 100.0,
          flightAltitude: altitudeValue.value,
          cycle_s: distance / speedValue.value,
          uuu: trackData.data.isup
        });
      }
    } catch (error) {
      console.error('任务执行失败:', error);
    }
  }
  isExecTask.value = false;
};

const clearTrackList = () => {
  if (trackDataList.value.length > 0) {
    current_x.value = trackDataList.value[0].data.startY;
    current_y.value = -trackDataList.value[0].data.startX;
  }
  trackDataList.value = [];
  clearCanvas();
};

const clearCanvas = () => {
  canvasConst.clear();
  drawAxes();
  addAirplaneImage();
  if (flightStatus.value) {
    addHomePositionImage();
  }
};

const addDrawingEvents = () => {
  canvasConst.on('mouse:wheel', (opt) => {
    const delta = opt.e.deltaY;
    let zoom = canvasConst.getZoom();
    zoom *= 0.999 ** delta;
    if (zoom > 20) zoom = 20;
    if (zoom < 0.01) zoom = 0.01;
    canvasConst.zoomToPoint({x: opt.e.offsetX, y: opt.e.offsetY}, zoom);
    updateScaleText(zoom);
    opt.e.preventDefault();
    opt.e.stopPropagation();
  });

  canvasConst.on('object:scaling', () => {
    updateScaleText(canvasConst.getZoom());
  });

  canvasConst.on('mouse:down', (opt) => {
    const evt = opt.e;
    if (evt.altKey === true) {
      isDragging = true;
      lastPosX = evt.clientX;
      lastPosY = evt.clientY;
    } else if (drawingMode.value === 'line' && isDrawing) {
      if (opt.e.button === 0) {
        finishDrawingLine(opt);
      } else if (opt.e.button === 2) {
        cancelDrawingLine();
      }
    } else if (drawingMode.value === 'circle' && isDrawing) {
      if (opt.e.button === 0) {
        finishDrawingCircle(opt);
      } else if (opt.e.button === 2) {
        cancelDrawingCircle();
      }
    } else if (drawingMode.value === 'rectangle' && isDrawing) {
      if (opt.e.button === 0) {
        finishDrawingRectangle(opt);
      } else if (opt.e.button === 2) {
        cancelDrawingRectangle();
      }
    } else if (opt.e.button === 2) {
      handleContextMenu(opt);
    } else if (opt.e.button === 0) {
      handleClickOutside();
    }
  });

  canvasConst.on('mouse:move', (opt) => {
    if (isDragging) {
      const e = opt.e;
      const vpt = canvasConst.viewportTransform;
      vpt[4] += e.clientX - lastPosX;
      vpt[5] += e.clientY - lastPosY;
      canvasConst.requestRenderAll();
      lastPosX = e.clientX;
      lastPosY = e.clientY;
    } else if (drawingMode.value === 'line' && isDrawing) {
      drawLine(opt);
    } else if (drawingMode.value === 'circle' && isDrawing) {
      drawCircle(opt);
    } else if (drawingMode.value === 'rectangle' && isDrawing) {
      drawRectangle(opt);
    }
  });

  canvasConst.on('mouse:up', () => {
    if (isDragging) {
      isDragging = false;
    }
  });
};

const drawAxes = () => {
  const width = canvasConst.getWidth();
  const height = canvasConst.getHeight();

  // 创建坐标轴
  const xAxis = new fabric.Line([-width * 10, 0, width * 10, 0], {
    stroke: '#ccc',
    strokeWidth: 5,
    selectable: false,
  });

  const yAxis = new fabric.Line([0, -height * 10, 0, height * 10], {
    stroke: '#ccc',
    strokeWidth: 5,
    selectable: false,
  });

  canvasConst.add(xAxis);
  canvasConst.add(yAxis);

  // 添加网格线
  const gridLineOptions = {
    stroke: '#888',
    strokeWidth: 1,
    selectable: false,
  };

  // 绘制网格
  for (let i = 0; i <= width * 10; i += gridSpacing) {
    if (i !== 0) {
      const line_l = new fabric.Line([i, -height * 10, i, height * 10], gridLineOptions);
      const line_r = new fabric.Line([-i, -height * 10, -i, height * 10], gridLineOptions);
      canvasConst.add(line_l);
      canvasConst.add(line_r);
    }
  }

  for (let j = 0; j <= height * 10; j += gridSpacing) {
    if (j !== 0) {
      const line_t = new fabric.Line([-width * 10, j, width * 10, j], gridLineOptions);
      const line_b = new fabric.Line([-width * 10, -j, width * 10, -j], gridLineOptions);
      canvasConst.add(line_t);
      canvasConst.add(line_b);
    }
  }

  canvasConst.renderAll();
};

const updateScaleText = (zoom) => {
  const scalePercentage = Math.round(zoom * 100);
  scale.value = zoom;
  scaleText.value = `Scale: ${scalePercentage}%`;
};

// 轨迹绘制方法
const setDrawingModeLine = () => {
  drawingMode.value = 'line';
  startDrawingLine();
};

const startDrawingLine = () => {
  isDrawing = true;
  const points = [current_x.value, current_y.value, current_x.value, current_y.value];
  const line = new fabric.Line(points, {
    strokeWidth: 5,
    stroke: 'red',
    originX: 'center',
    originY: 'center',
    selectable: false
  });
  canvasConst.add(line);
  canvasConst._currentLine = line;
};

const drawLine = (opt) => {
  const pointer = canvasConst.getPointer(opt.e);
  const line = canvasConst._currentLine;
  line.set({x2: pointer.x, y2: pointer.y});
  canvasConst.renderAll();
};

const finishDrawingLine = (opt) => {
  isDrawing = false;
  const pointer = canvasConst.getPointer(opt.e);
  const lineData = {
    ...LineData,
    startX: -current_y.value,
    startY: current_x.value,
    endX: -pointer.y,
    endY: pointer.x,
  };

  trackDataList.value.push({
    type: 'line',
    data: lineData,
  });

  current_x.value = pointer.x;
  current_y.value = pointer.y;
  canvasConst._currentLine = null;
};

const cancelDrawingLine = () => {
  isDrawing = false;
  canvasConst.remove(canvasConst._currentLine);
  canvasConst._currentLine = null;
};

const setDrawingModeCircle = () => {
  drawingMode.value = 'circle';
  startDrawingCircle();
};

const startDrawingCircle = () => {
  isDrawing = true;
  const circle = new fabric.Circle({
    left: current_x.value - 10,
    top: current_y.value - 10,
    radius: 10,
    strokeWidth: 5,
    fill: 'rgba(0,0,0,0)',
    stroke: 'red',
    selectable: false
  });
  canvasConst.add(circle);
  canvasConst._currentCircle = circle;
};

const drawCircle = (opt) => {
  const pointer = canvasConst.getPointer(opt.e);
  const startPoint = {x: current_x.value, y: current_y.value};
  const radius = Math.sqrt(Math.pow(pointer.x - startPoint.x, 2) + Math.pow(pointer.y - startPoint.y, 2));
  const circle = canvasConst._currentCircle;

  if (pointer.y < startPoint.y) {
    circle.set({radius, left: startPoint.x - radius, top: startPoint.y - 2 * radius});
  } else {
    circle.set({radius, left: startPoint.x - radius, top: startPoint.y});
  }

  canvasConst.renderAll();
};

const finishDrawingCircle = (opt) => {
  isDrawing = false;
  const pointer = canvasConst.getPointer(opt.e);
  const startPoint = {x: current_x.value, y: current_y.value};
  const radius = Math.sqrt(Math.pow(pointer.x - startPoint.x, 2) + Math.pow(pointer.y - startPoint.y, 2));

  const circleData = {
    ...CircleData,
    startX: -current_y.value,
    startY: current_x.value,
    radius: radius,
    isup: pointer.y < startPoint.y
  };

  trackDataList.value.push({
    type: 'circle',
    data: circleData,
  });

  canvasConst._currentCircle.set({radius});
  canvasConst._currentCircle = null;
};

const cancelDrawingCircle = () => {
  isDrawing = false;
  canvasConst.remove(canvasConst._currentCircle);
  canvasConst._currentCircle = null;
};

const setOriginToCenter = () => {
  const width = canvasConst.getWidth();
  const height = canvasConst.getHeight();
  canvasConst.viewportTransform[4] = width / 2;
  canvasConst.viewportTransform[5] = height / 2;
};

const setDrawingModeRectangle = () => {
  drawingMode.value = 'rectangle';
  startDrawingRectangle();
};

const startDrawingRectangle = () => {
  isDrawing = true;
  const rect = new fabric.Rect({
    left: current_x.value,
    top: current_y.value,
    width: 0,
    height: 0,
    stroke: 'red',
    strokeWidth: 5,
    fill: 'rgba(0,0,0,0)',
    selectable: false
  });
  canvasConst.add(rect);
  canvasConst._currentRectangle = rect;
};

const drawRectangle = (opt) => {
  const pointer = canvasConst.getPointer(opt.e);
  const rect = canvasConst._currentRectangle;
  const left = Math.min(current_x.value, pointer.x);
  const top = Math.min(current_y.value, pointer.y);
  const width = Math.abs(pointer.x - current_x.value);
  const height = Math.abs(pointer.y - current_y.value);
  rect.set({left, top, width, height});
  canvasConst.renderAll();
};

const finishDrawingRectangle = (opt) => {
  isDrawing = false;
  const pointer = canvasConst.getPointer(opt.e);
  const rectData = {
    ...RectangleData,
    startX: -current_y.value,
    startY: current_x.value,
    endX: -pointer.y,
    endY: pointer.x,
  };

  trackDataList.value.push({
    type: 'rectangle',
    data: rectData,
  });

  canvasConst._currentRectangle = null;
};

const cancelDrawingRectangle = () => {
  isDrawing = false;
  canvasConst.remove(canvasConst._currentRectangle);
  canvasConst._currentRectangle = null;
};

const drawSmoothCurve = (x, y) => {
  let temp = x.valueOf();
  x = y.valueOf();
  y = -temp;

  const pathString = `M ${pre_y.value} ${-pre_x.value} Q ${(pre_y.value + x) / 2} ${(-pre_x.value + y) / 2} ${x} ${y}`;
  const path = new fabric.Path(pathString, {
    stroke: 'red',
    strokeWidth: 5,
    fill: 'transparent',
    selectable: false,
    evented: false,
  });

  pre_x.value = -y;
  pre_y.value = x;
  canvasConst.add(path);
  canvasConst.renderAll();
};

function connect(){
  if(ws == null)
    ws =  new WebSocket("ws://localhost:9090/ws/messages");
  ws.onmessage = onMessage;
  ws.onopen = () => console.log("WebSocket连接已建立");
  ws.onclose = () => {
    isConnected.value = false;
    customModeText.value = "未知";
    systemStatusText.value = "未解锁"
    ws.close();
    ws = null;
    //重新连接
    connect()
    console.log("WebSocket连接已关闭")
  };
  ws.onerror = (error) => console.error("WebSocket错误:", error);
}

onMounted(() => {
  document.addEventListener('contextmenu', banContextMenu);
  connect()
  fetchFlyTasks();

  // 初始化画布
  canvasConst = new fabric.Canvas(canvas.value, {
    fireRightClick: true,
    stopContextMenu: true,
  });

  // 添加事件监听
  addDrawingEvents();
  addAirplaneImage();

  // 设置画布大小
  const resizeCanvas = () => {
    const containerWidth = document.querySelector('.map-container').clientWidth;
    const containerHeight = document.querySelector('.map-container').clientHeight;

    canvasConst.setWidth(containerWidth);
    canvasConst.setHeight(containerHeight);

    if (isFirst.value) {
      setOriginToCenter();
      drawAxes();
      isFirst.value = false;
    }

    canvasConst.renderAll();
  };

  resizeCanvas();
  window.addEventListener('resize', resizeCanvas);

  // 清除事件监听器
  onUnmounted(() => {
    window.removeEventListener('resize', resizeCanvas);
    document.removeEventListener('contextmenu', banContextMenu);
    ws.close();
  });
});

const fetchFlyTasks = async () => {
  try {
    const response = await axios.get('http://localhost:9090/flytask/getAll');
    flyTaskList.value = response.data.data || [];
    console.log("任务信息："+flyTaskList.value)
  } catch (error) {
    console.error('获取飞行任务失败:', error);
  }
};
</script>

<style scoped>
/* 整体布局 */
.app-container {
  display: flex;
  flex-direction: column;
  width: 100vw;
  height: 100vh;
  background: linear-gradient(180deg, #0a2a5a, #1a5ab5);
  overflow: hidden;
  padding: 15px;
  box-sizing: border-box;
}

/* 顶部装饰区域 */
.top-decoration {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 60px;
  background: rgba(30, 50, 80, 0.6);
  border-radius: 12px;
  padding: 0 20px;
  margin-bottom: 15px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

.logo {
  display: flex;
  justify-content: start;
  //gap: 15px;
}

.logo img {
  height: 40px;
}

.logo h1 {
  color: #fff;
  font-size: 28px;
  margin-left: 520px;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  font-weight: bold;
  font-family: 'Arial', sans-serif;
}

.status-indicator {
  display: flex;
  gap: 20px;

}

.connection-status {
  padding: 6px 15px;
  border-radius: 20px;
  background: #2ecc71;
  color: white;
  font-weight: bold;
  font-size: 14px;
}

.connection-status.connected {
  background: #2ecc71;
}

.mode-indicator {
  padding: 6px 15px;
  border-radius: 20px;
  background: rgba(100, 255, 218, 0.2);
  color: #64ffda;
  font-weight: bold;
  font-size: 14px;
}

/* 主内容区域 */
.main-content {
  display: flex;
  flex: 1;
  gap: 15px;
  overflow: hidden;
}

/* 左侧面板 */
.left-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

/* 画布容器 */
.map-container {
  flex-grow: 1;
  position: relative;
  overflow: hidden;
  //background: rgba(15, 30, 60, 0.7);
  background: linear-gradient(180deg, rgba(15, 30, 60, 0.7), #0f4288);

  border-radius: 15px;
  border: 2px solid rgba(100, 255, 218, 0.2);
  box-shadow: 0 8px 25px rgba(0, 0, 0, 0.4);
}

canvas {
  width: 100%;
  height: 100%;
  display: block;
}

.scale-indicator {
  position: absolute;
  bottom: 10px;
  right: 10px;
  background-color: rgba(255, 255, 255, 0.8);
  padding: 5px 10px;
  border-radius: 5px;
  font-size: 14px;
  pointer-events: none;
  color: black;
}

/* 右侧控制面板 */
.right-panel {
  width: 350px;
  display: flex;
  flex-direction: column;
  gap: 15px;
}

/* 任务中心 */
.task-center {
  background: rgba(30, 50, 80, 0.7);
  border-radius: 12px;
  padding: 15px;
  border: 1px solid rgba(100, 255, 218, 0.1);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
  height: 200px;
}

.task-title {
  font-size: 18px;
  font-weight: 600;
  color: #64ffda;
  margin-bottom: 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.refresh-button {
  background: transparent;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 5px;
}

.refresh-button img {
  width: 20px;
  height: 20px;
}

.scroll {
  height: 230px;
  overflow-y: auto;
  padding: 5px;
}

.list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.list-item {
  display: flex;
  align-items: center;
  background: rgba(40, 60, 90, 0.9);
  border-radius: 8px;
  padding: 10px;
  transition: all 0.3s ease;
}

.list-item:hover {
  background: rgba(50, 70, 100, 0.9);
}

.task-icon {
  width: 40px;
  height: 40px;
  margin-right: 12px;
}

.task-info {
  flex: 1;
}

.task-row {
  font-size: 14px;
  margin-bottom: 4px;
  color: #e6f1ff;
}

.task-value {
  font-size: 12px;
  color: #8892b0;
}

.task-btn {
  background: rgba(100, 255, 218, 0.1);
  border: 1px solid rgba(100, 255, 218, 0.3);
  color: #64ffda;
  padding: 6px 12px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s ease;
}

.task-btn:hover {
  background: rgba(100, 255, 218, 0.2);
}

/* 控制面板通用样式 */
.panel-section {
  background: rgba(30, 50, 80, 0.7);
  border-radius: 12px;
  padding: 15px;
  border: 1px solid rgba(100, 255, 218, 0.1);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}

.section-title {
  font-size: 18px;
  font-weight: 600;
  color: #64ffda;
  margin-bottom: 15px;
  text-align: center;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(100, 255, 218, 0.2);
}

.button-row {
  display: flex;
  gap: 12px;
  margin-bottom: 12px;
}

.button-row:last-child {
  margin-bottom: 0;
}

.control-button {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(40, 60, 90, 0.8);
  border: 1px solid rgba(100, 255, 218, 0.15);
  border-radius: 10px;
  color: #e6f1ff;
  cursor: pointer;
  transition: all 0.3s ease;
  padding: 12px 8px;
  height: 90px;
}

.control-button:hover {
  background: rgba(100, 255, 218, 0.1);
  transform: translateY(-3px);
}

.control-button:active {
  transform: translateY(0);
}

.control-button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  transform: none;
}

.image_button {
  width: 40px;
  height: 40px;
  margin-bottom: 8px;
}

.button-label {
  font-size: 14px;
  font-weight: 500;
  text-align: center;
}

/* 状态网格布局 */
.status-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
}

.status-card {
  background: rgba(35, 55, 85, 0.8);
  border-radius: 10px;
  padding: 12px;
  border: 1px solid rgba(100, 255, 218, 0.1);
  text-align: center;
}

.status-label {
  font-size: 13px;
  color: #8892b0;
  margin-bottom: 6px;
}

.status-value {
  font-size: 20px;
  font-weight: 600;
  color: #64ffda;
}

.status-unit {
  font-size: 13px;
  color: #8892b0;
  margin-left: 4px;
}

/* 底部飞行数据 */
.bottom-data {
  display: flex;
  justify-content: space-around;
  height: 60px;
  background: rgba(30, 50, 80, 0.6);
  border-radius: 12px;
  padding: 0 20px;
  margin-top: 15px;
  align-items: center;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}

.data-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.data-label {
  font-size: 16px;
  color: #64ffda;
  font-weight: 500;
}

.data-value {
  font-size: 16px;
  color: #fff;
  font-weight: 600;
}

/* 滚动条样式 */
.scroll::-webkit-scrollbar {
  width: 6px;
}

.scroll::-webkit-scrollbar-track {
  background: rgba(10, 25, 47, 0.3);
  border-radius: 3px;
}

.scroll::-webkit-scrollbar-thumb {
  background: rgba(100, 255, 218, 0.3);
  border-radius: 3px;
}

.scroll::-webkit-scrollbar-thumb:hover {
  background: rgba(100, 255, 218, 0.5);
}
.dialog-overlay {
  position: fixed;
  top: 25%;
  left: 25%;
  width: 50%;
  height: 50%;
  background: rgba(0, 0, 0, 0);
  display: flex;
  justify-content: center;
  border-radius: 15px;
  align-items: center;
}

.dialog {
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  width: 300px;
  text-align: center;
}

.dialog-header {
  padding: 12px 16px;
  background-color: #f5f7fa;
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #ebeef5;
}

.dialog-header h3 {
  margin: 0;
  font-size: 16px;
  color: #303133;
}

.close-btn {
  background: none;
  border: none;
  font-size: 18px;
  color: #909399;
  cursor: pointer;
}

.close-btn:hover {
  color: #606266;
}

.dialog-content {
  flex: 1;
  padding: 16px;
  overflow-y: auto;
}

.task-info-item {
  display: flex;
  align-items: center;
  margin-bottom: 12px;
}

.info-label {
  width: 100px;
  color: #606266;
  font-size: 14px;
}

.info-value {
  flex: 1;
  color: #303133;
  font-size: 14px;
}

.client-icon {
  width: 16px;
  height: 16px;
  margin-right: 5px;
  vertical-align: middle;
}

.track-data {
  display: inline-block;
  max-width: 280px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}

.dialog-footer {
  padding: 12px 16px;
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  background-color: #f5f7fa;
  border-top: 1px solid #ebeef5;
}

.btn {
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
  font-size: 14px;
}

.cancel-btn {
  background-color: white;
  border: 1px solid #dcdfe6;
  color: #606266;
}

.cancel-btn:hover {
  background-color: #f5f7fa;
}

.confirm-btn {
  background-color: #409eff;
  border: 1px solid #409eff;
  color: white;
}

.confirm-btn:hover {
  background-color: #66b1ff;
}
.status-indicator {
  display: flex;
  gap: 20px;
  align-items: center;
}

.speed-mode-button {
  background: rgba(100, 255, 218, 0.1);
  border: 1px solid rgba(100, 255, 218, 0.3);
  color: #64ffda;
  padding: 6px 15px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 14px;
  transition: all 0.3s ease;
}

.speed-mode-button:hover {
  background: rgba(100, 255, 218, 0.2);
}
.dialog-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}

.dialog {
  background: rgba(30, 50, 80, 0.9); /* 蓝色背景 */
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
  width: 300px;
  text-align: center;
  color: #64ffda; /* 字体颜色 */
}

.dialog h3 {
  margin-top: 0;
  font-size: 1.5em;
  color: #64ffda;
}

.setting-item {
  margin: 15px 0;
  text-align: left;
}

.setting-item label {
  display: block;
  margin-bottom: 5px;
  font-size: 14px;
  color: #64ffda;
}

.setting-item input[type="range"] {
  width: 100%;
  margin-bottom: 10px;
}

.setting-item p {
  margin: 0;
  font-size: 14px;
  color: #64ffda;
}

.button-container {
  display: flex;
  justify-content: center;
  margin-top: 20px;
}

.button-container button {
  padding: 8px 16px;
  margin: 0 10px;
  border: none;
  border-radius: 4px;
  font-size: 14px;
  cursor: pointer;
  transition: background-color 0.3s;
}

.button-container button:first-child {
  background-color: #409eff; /* 蓝色按钮 */
  color: white;
}

.button-container button:first-child:hover {
  background-color: #66b1ff;
}

.button-container button:last-child {
  background-color: #f44336; /* 红色按钮 */
  color: white;
}

.button-container button:last-child:hover {
  background-color: #da190b;
}
</style>